﻿using System;
using System.IO;
using System.Reflection;
using System.Diagnostics;

using SBPweb.Forge.Modules.Resources;

namespace SBPweb.Forge.Modules.Modularity
{
    /// <summary>
    /// This class represents some information about Module.
    /// </summary>
    public class ModuleDescriptor
    {

		#region Private & Protected members
		
		/// <summary>
		/// byte[] mRawData
		/// </summary>
		private byte[] rawData;
		/// <summary>
		/// string mModuleTypeName
		/// </summary>
        protected string moduleTypeName;
        /// <summary>
        /// FileInfo pFileInfo
        /// </summary>
		protected FileInfo fileInfo;
        /// <summary>
        /// bool pLoaded
        /// </summary>
		protected bool isLoaded;
        /// <summary>
        /// bool pInitialized
        /// </summary>
		protected bool isInitialized;
        /// <summary>
        /// string pAssemblyName
        /// </summary>
		protected string assemblyName;
        /// <summary>
        /// System.Version pAssemblyVersion
        /// </summary>
		protected System.Version assemblyVersion;
		/// <summary>
		/// System.Version pFileVersion
		/// </summary>
		protected string fileVersion;
		/// <summary>
		/// string pFileName
		/// </summary>
		protected string fileName;
		/// <summary>
		/// Assembly pAssembly
		/// </summary>
		protected Assembly assembly;
		/// <summary>
		/// ConstructorInfo pConstructorInfo
		/// </summary>
		protected ConstructorInfo constructorInfo;
		/// <summary>
		/// ModuleProfile pModuleProfile
		/// </summary>
		protected ModuleProfile moduleProfile;

		#endregion

		#region Constructor logic

		internal ModuleDescriptor(FileInfo fileInfo, ModuleProfile mp)
        {
            try
            {
				this.fileInfo = fileInfo;
                this.isLoaded = false;
                this.isInitialized = false;

                this.rawData = null;
                this.moduleTypeName = null;

                this.rawData = GetBytes(fileInfo.FullName);
                this.assembly = Assembly.LoadFrom(fileInfo.FullName);
                this.assemblyName = assembly.GetName().Name;
                this.assemblyVersion = assembly.GetName().Version;

                this.fileName = fileInfo.FullName;

				FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(fileInfo.FullName);
                this.fileVersion = fvi.FileVersion;

				object obj = ResourceHandler.GetAssemblyCustomAttribute<AssemblyDefaultAliasAttribute>(assembly);

                this.moduleTypeName = obj.ToString();

				Type type = assembly.GetType(moduleTypeName);
                this.constructorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(IModuleHost) }, null);

                this.moduleProfile = mp;

            }
            catch (Exception ex)
            {
                throw new ArgumentException(string.Format("FileInfo parameter error ({0})!", fileInfo.FullName), ex);
            }
		}

        public static ModuleDescriptor CreateInstance(FileInfo fileInfo)
        {
            ModuleProfile mp = ModuleProfile.CreateInstance(fileInfo);
            return new ModuleDescriptor(fileInfo, mp);
        }

		#endregion

		#region Properties

		/// <summary>
		/// Raw data of assembly
		/// </summary>
		internal byte[] RawData
        {
            get
            {
                return rawData;
            }
        }

        /// <summary>
        /// Name of the entrypoint Type of Module
        /// </summary>
        public string ModuleTypeName
        {
            get
            {
                return moduleTypeName;
            }
        }

        /// <summary>
        /// FileInfo of Module
        /// </summary>
		public FileInfo FileInfo
		{
			get
			{
				return fileInfo;
			}
		}

        /// <summary>
        /// This property is true if module is loaded
        /// </summary>
		public bool Loaded
		{
			get
			{
				return isLoaded;
			}
			internal set
			{
				isLoaded = value;
			}
		}

        /// <summary>
        /// This property is true if module is initialized
        /// </summary>
        public bool Initialized
		{
			get
			{
				return isInitialized;
			}
			internal set
			{
				isInitialized = value;
			}
		}

        /// <summary>
        /// AssemblyName of the Module
        /// </summary>
		public string AssemblyName
		{
			get
			{
				return assemblyName;
			}
		}

        /// <summary>
        /// AssemblyVersion of the Module
        /// </summary>
		public System.Version AssemblyVersion
		{
			get
			{
				return assemblyVersion;
			}
		}

		/// <summary>
		/// FileVersion of the Module
		/// </summary>
		public string FileVersion
		{
			get
			{
				return fileVersion;
			}
		}

		/// <summary>
		/// Full name of the assembly file
		/// </summary>
		public string FileName
		{
			get
			{
				return fileName;
			}
		}

		/// <summary>
		/// The Assembly instance of the module
		/// </summary>
		internal Assembly Assembly
		{
			get
			{
				return assembly;
			}
		}

		/// <summary>
		/// The ConstructorInfo instance of the module
		/// </summary>
		internal ConstructorInfo ConstructorInfo
		{
			get
			{
				return constructorInfo;
			}
		}

		/// <summary>
		/// The ModuleProfile instance of the module
		/// </summary>
		public ModuleProfile ModuleProfile
		{
			get
			{
				return moduleProfile;
			}
		}

		#endregion

		#region Internal methods

		internal static byte[] GetBytes(string path)
        {
            byte[] rawData;
            FileStream fS = new FileStream(path, FileMode.Open, FileAccess.Read);
            int length = (int)fS.Length;
            rawData = (byte[])Array.CreateInstance(typeof(byte), length);
            fS.Read(rawData, 0, length);
            fS.Close();

            return rawData;
		}

		#endregion

	}
}